﻿#include <learn/topo/topo_explorer.h>

using namespace xi;
using namespace xi::topo;

VHandle Topo_Explorer::start_vertex(CHandle co)
{
    if (co == nullptr)
        return nullptr;

    VHandle v = nullptr;
    if (co->edge()->coedge() == co)
        v = co->edge()->start();
    else
        v = co->edge()->end();
    return v;
}

VHandle Topo_Explorer::end_vertex(CHandle co)
{
    if (co == nullptr)
        return nullptr;

    VHandle v = nullptr;
    if (co->edge()->coedge() == co)
        v = co->edge()->end();
    else
        v = co->edge()->start();
    return v;
}

std::vector<VHandle> Topo_Explorer::vertices_on_face(FHandle f)
{
    if (f == nullptr)
        return {};

    std::vector<VHandle> vList;

    // 取第一个 loop 上的所有顶点
    auto loop = f->wire();
    CHandle co = loop->coedge();
    vList.push_back(start_vertex(co));

    while (co->next() != loop->coedge())
    {
        vList.push_back(end_vertex(co));
        co = co->next();
    }
    return vList;
}

std::vector<EHandle> Topo_Explorer::edges_on_face(FHandle f)
{
    if (f == nullptr)
        return {};

    std::vector<EHandle> eList;

    // 取第一个 loop 上的所有顶点
    auto loop = f->wire();
    CHandle co = loop->coedge();
    eList.push_back(co->edge());

    while (co->next() != loop->coedge())
    {
        co = co->next();
        eList.push_back(co->edge());
    }
    return eList;
}

std::vector<CHandle> Topo_Explorer::coedges_on_face(FHandle f)
{
    if (f == nullptr)
        return {};

    std::vector<CHandle> coList;

    // 取第一个 loop 上的所有顶点
    auto loop = f->wire();
    CHandle co = loop->coedge();
    coList.push_back(co);

    while (co->next() != loop->coedge())
    {
        co = co->next();
        coList.push_back(co);
    }
    return coList;
}

CHandle Topo_Explorer::common_coedge(VHandle v0, VHandle v1)
{
    if (v0 == nullptr || v1 == nullptr)
        return nullptr;

    // 首先获得连接 v 的边
    auto &eList = v0->edges();
    for (auto e : eList)
    {
        if (e->start() == v0 && e->end() == v1)
            return e->coedge();
        if (e->start() == v1 && e->end() == v0)
            return e->coedge()->twin();
    }
    return nullptr;
}

EHandle Topo_Explorer::common_edge(VHandle v0, VHandle v1)
{
    if (v0 == nullptr || v1 == nullptr)
        return nullptr;

    // 首先获得连接 v 的边
    auto &eList = v0->edges();
    for (auto e : eList)
    {
        if (e->start() == v0 && e->end() == v1)
            return e;
        if (e->start() == v1 && e->end() == v0)
            return e;
    }
    return nullptr;
}

std::vector<EHandle> Topo_Explorer::common_edges(FHandle f0, FHandle f1)
{
    if (f0 == nullptr || f1 == nullptr)
        return {};

    std::vector<EHandle> eList;
    auto loop0 = f0->wire();
    auto loop1 = f1->wire();

    CHandle co0 = loop0->coedge();
    CHandle co1 = loop1->coedge();

    do
    {
        do
        {
            // 循环记录公共边
            if (co0->edge() == co1->edge())
            {
                eList.push_back(co0->edge());
                break;
            }

            co1 = co1->next();
        } while (co1 != loop1->coedge());
        co0 = co0->next();
        co1 = loop1->coedge();
    } while (co0 != loop0->coedge());

    return eList;
}

std::unordered_set<VHandle> Topo_Explorer::adjacent_vertices(VHandle v)
{
    if (v == nullptr)
        return {};

    std::unordered_set<VHandle> vList;

    // 首先获得连接 v 的边
    auto &eList = v->edges();
    for (auto e : eList)
    {
        if (e->start() == v)
            vList.insert(e->end());
        else
            vList.insert(e->start());
    }
    return vList;
}

std::unordered_set<CHandle> Topo_Explorer::adjacent_coedges(VHandle v)
{
    if (v == nullptr)
        return {};

    std::unordered_set<CHandle> coList;

    // 首先获得连接 v 的边
    auto &eList = v->edges();
    for (auto e : eList)
    {
        if (e->start() == v)
            coList.insert(e->coedge());
        else
            coList.insert(e->coedge()->twin());
    }
    return coList;
}

std::unordered_set<EHandle> Topo_Explorer::adjacent_edges(EHandle e)
{
    if (e == nullptr)
        return {};

    std::unordered_set<EHandle> eList;
    auto &eList0 = e->start()->edges();
    auto &eList1 = e->end()->edges();

    for (auto e0 : eList0)
        eList.insert(e0);
    for (auto e1 : eList1)
        eList.insert(e1);
    eList.erase(e);

    return eList;
}

std::unordered_set<FHandle> Topo_Explorer::adjacent_faces(VHandle v)
{
    if (v == nullptr)
        return {};

    // 使用 set 避免重复元素
    std::unordered_set<FHandle> fList;

    // 首先获得连接 v 的边
    auto &eList = v->edges();
    for (auto e : eList)
    {
        if (e->coedge()->wire() != nullptr && e->coedge()->wire()->face() != nullptr)
            fList.insert(e->coedge()->wire()->face());
        if (e->coedge()->twin()->wire() != nullptr && e->coedge()->twin()->wire()->face() != nullptr)
            fList.insert(e->coedge()->twin()->wire()->face());
    }
    return fList;
}

std::unordered_set<FHandle> Topo_Explorer::adjacent_faces(FHandle f)
{
    if (f == nullptr)
        return {};

    // 使用 set 避免重复元素
    std::unordered_set<FHandle> fList;

    // 首先获得 f 的所有边
    for (auto e : edges_on_face(f))
    {
        if (e->coedge()->wire() != nullptr && e->coedge()->wire()->face() != nullptr)
            fList.insert(e->coedge()->wire()->face());
        if (e->coedge()->twin()->wire() != nullptr && e->coedge()->twin()->wire()->face() != nullptr)
            fList.insert(e->coedge()->twin()->wire()->face());
    }
    fList.erase(f);

    return fList;
}

std::deque<EHandle> Topo_Explorer::adjacent_ordered_edges(CHandle co)
{
    if (co == nullptr)
        return {};

    std::deque<EHandle> eList;

    // 找到第一个边的起点
    // 先逆时针寻找
    auto e = co;
    while (e != nullptr)
    {
        eList.push_back(e->edge());
        e = e->prev();

        // 如果回到初始边，就退出
        if (e == nullptr || e->twin() == co)
            break;

        e = e->twin();
    }

    // 如果没有回到初始边，就顺时针寻找
    if (e == nullptr)
    {
        e = co->twin()->next();
        while (e != nullptr)
        {
            eList.push_front(e->edge());
            e = e->twin()->next();
        }
        // 这里不需要判断回到初始边，因为如果一个方向不能返回，那么反过来也不能返回
    }

    return eList;
}

std::unordered_set<CHandle> Topo_Explorer::edges(Topo_Wire *wire)
{
    if (wire == nullptr || wire->coedge() == nullptr)
        return {};

    std::unordered_set<CHandle> eList;

    CHandle co = wire->coedge();
    do
    {
        eList.insert(co);
        co = co->next();
    } while (co != wire->coedge());

    return eList;
}

std::unordered_set<Topo_Wire *> Topo_Explorer::wires(Topo_Face *face)
{
    if (face == nullptr)
        return {};

    std::unordered_set<Topo_Wire *> wList;

    Topo_Wire *wire = face->wire();
    do
    {
        wList.insert(wire);
        wire = wire->next();
    } while (wire != nullptr);

    return wList;
}

std::unordered_set<Topo_Wire *> Topo_Explorer::wires(Topo_Shell *shell)
{
    if (shell == nullptr)
        return {};

    std::unordered_set<Topo_Wire *> wList;
    Topo_Shell *s = shell;

    auto w = s->wire();
    if (w != nullptr)
    {
        wList.insert(w);
        return wList;
    }

    auto subshells = s->subshells();
    if (!subshells.empty())
    {
        for (auto s : subshells)
        {
            auto ws = wires(s);
            wList.insert(ws.begin(), ws.end());
        }
    }
    return wList;
}

std::unordered_set<Topo_Face *> Topo_Explorer::faces(Topo_Shell *shell)
{
    if (shell == nullptr)
        return {};

    std::unordered_set<Topo_Face *> fList;
    Topo_Shell *s = shell;

    auto f = s->face();
    if (f != nullptr)
    {
        fList.insert(f);
        return fList;
    }

    auto subshells = s->subshells();
    if (!subshells.empty())
    {
        for (auto s : subshells)
        {
            auto fs = faces(s);
            fList.insert(fs.begin(), fs.end());
        }
    }
    return fList;
}